/******************************************************************************

	COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2010.

	This file is part of the Maxsi Library.

	Maxsi Library is free software: you can redistribute it and/or modify it
	under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or (at your
	option) any later version.

	Maxsi Library is distributed in the hope that it will be useful, but
	WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
	or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
	License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with Maxsi Library. If not, see <http://www.gnu.org/licenses/>.

	Maxsi Library
	A powerful Cross-Platform C++ General Purpose Library that allows you to
	efficiently create high-performance and reliable applications.

	MaxsiInteger.h
	Useful functions for dealing with integers.

******************************************************************************/

BeginMaxsiNamespace

//=============================================================================
// Divides two integers and rounds up instead of down.
//=============================================================================
#define Maxsi__DivUp(a, b) ( (a + b - 1) / b)
#define Maxsi__DivDown(a, b) ( a / b)

//=============================================================================
//	Redirect some functions depending on the current string type.
//=============================================================================
#ifdef Maxsi_Using_Unicode_Internally

	#define Maxsi__PrintUIntM10 PrintUIntW10
	#define Maxsi__PrintUInt8M10 PrintUInt8W10
	#define Maxsi__PrintUInt16M10 PrintUInt16W10
	#define Maxsi__PrintUInt32M10 PrintUInt32W10
	#define Maxsi__PrintUInt64M10 PrintUInt64W10
	#define Maxsi__PrintUIntM16X PrintUIntW16X
	#define Maxsi__PrintUInt8M16X PrintUInt8W16X
	#define Maxsi__PrintUInt16M16X PrintUInt16W16X
	#define Maxsi__PrintUInt32M16X PrintUInt32W16X
	#define Maxsi__PrintUInt64M16X PrintUInt64W16X
	#define Maxsi__PrintSizeM10 PrintSizeW10
	#define Maxsi__PrintSizeM16X PrintSizeW16X

	#define Maxsi__ReadIntM10 ReadIntW10
	#define Maxsi__ReadInt8M10 ReadInt8W10
	#define Maxsi__ReadInt16M10 ReadInt16W10
	#define Maxsi__ReadInt32M10 ReadInt32W10
	#define Maxsi__ReadInt64M10 ReadInt64W10
	#define Maxsi__ReadUIntM10 ReadUIntW10
	#define Maxsi__ReadUInt8M10 ReadUInt8W10
	#define Maxsi__ReadUInt16M10 ReadUInt16W10
	#define Maxsi__ReadUInt32M10 ReadUInt32W10
	#define Maxsi__ReadUInt64M10 ReadUInt64W10
	#define Maxsi__ReadUIntM16 ReadUIntW16
	#define Maxsi__ReadUInt8M16 ReadUInt8W16
	#define Maxsi__ReadUInt16M16 ReadUInt16W16
	#define Maxsi__ReadUInt32M16 ReadUInt32W16
	#define Maxsi__ReadUInt64M16 ReadUInt64W16

#else

	#define Maxsi__PrintUIntM10 PrintUIntA10
	#define Maxsi__PrintUInt8M10 PrintUInt8A10
	#define Maxsi__PrintUInt16M10 PrintUInt16A10
	#define Maxsi__PrintUInt32M10 PrintUInt32A10
	#define Maxsi__PrintUInt64M10 PrintUInt64A10
	#define Maxsi__PrintUIntM16X PrintUIntA16X
	#define Maxsi__PrintUInt8M16X PrintUInt8A16X
	#define Maxsi__PrintUInt16M16X PrintUInt16A16X
	#define Maxsi__PrintUInt32M16X PrintUInt32A16X
	#define Maxsi__PrintUInt64M16X PrintUInt64A16X
	#define Maxsi__PrintSizeM10 PrintSizeA10
	#define Maxsi__PrintSizeM16X PrintSizeA16X

	#define Maxsi__ReadIntM10 ReadIntA10
	#define Maxsi__ReadInt8M10 ReadInt8A10
	#define Maxsi__ReadInt16M10 ReadInt16A10
	#define Maxsi__ReadInt32M10 ReadInt32A10
	#define Maxsi__ReadInt64M10 ReadInt64A10
	#define Maxsi__ReadUIntM10 ReadUIntA10
	#define Maxsi__ReadUInt8M10 ReadUInt8A10
	#define Maxsi__ReadUInt16M10 ReadUInt16A10
	#define Maxsi__ReadUInt32M10 ReadUInt32A10
	#define Maxsi__ReadUInt64M10 ReadUInt64A10
	#define Maxsi__ReadUIntM16 ReadUIntA16
	#define Maxsi__ReadUInt8M16 ReadUInt8A16
	#define Maxsi__ReadUInt16M16 ReadUInt16A16
	#define Maxsi__ReadUInt32M16 ReadUInt32A16
	#define Maxsi__ReadUInt64M16 ReadUInt64A16

#endif

//=============================================================================
//	If non namespaced macros are enabled (to avoid collisions with other stuff)
//	then make the Maxsi__ namespaced defines global.
//=============================================================================
#ifdef Maxsi_Enable_Non_Namespaced_Macros

	#define PrintUIntM10 Maxsi__PrintUIntM10
	#define PrintUInt8M10 Maxsi__PrintUInt8M10
	#define PrintUInt16M10 Maxsi__PrintUInt16M10
	#define PrintUInt32M10 Maxsi__PrintUInt32M10
	#define PrintUInt64M10 Maxsi__PrintUInt64M10
	#define PrintUIntM16X Maxsi__PrintUIntM16X
	#define PrintUInt8M16X Maxsi__PrintUInt8M16X
	#define PrintUInt16M16X Maxsi__PrintUInt16M16X
	#define PrintUInt32M16X Maxsi__PrintUInt32M16X
	#define PrintUInt64M16X Maxsi__PrintUInt64M16X
	#define PrintSizeM10 Maxsi__PrintSizeM10
	#define PrintSizeM16X Maxsi__PrintSizeM16X

	#define ReadIntM10 Maxsi__ReadIntM10
	#define ReadInt8M10 Maxsi__ReadInt8M10
	#define ReadInt16M10 Maxsi__ReadInt16M10
	#define ReadInt32M10 Maxsi__ReadInt32M10
	#define ReadInt64M10 Maxsi__ReadInt64M10
	#define ReadUIntM10 Maxsi__ReadUIntM10
	#define ReadUInt8M10 Maxsi__ReadUInt8M10
	#define ReadUInt16M10 Maxsi__ReadUInt16M10
	#define ReadUInt32M10 Maxsi__ReadUInt32M10
	#define ReadUInt64M10 Maxsi__ReadUInt64M10
	#define ReadUIntM16 Maxsi__ReadUIntM16
	#define ReadUInt8M16 Maxsi__ReadUInt8M16
	#define ReadUInt16M16 Maxsi__ReadUInt16M16
	#define ReadUInt32M16 Maxsi__ReadUInt32M16
	#define ReadUInt64M16 Maxsi__ReadUInt64M16

	#define DivUp Maxsi__DivUp
	#define DivDown Maxsi__DivDown

	#define UINT8_MAX_LEN_BASE_10 3 // RoundUp( N * LOG(2)/(LOG(10) )
	#define UINT16_MAX_LEN_BASE_10 5 // RoundUp( N * LOG(2)/(LOG(10) ) 
	#define UINT32_MAX_LEN_BASE_10 10 // RoundUp( N * LOG(2)/(LOG(10) ) 
	#define UINT64_MAX_LEN_BASE_10 20 // RoundUp( N * LOG(2)/(LOG(10) )

	#define FILESIZE_MAX_LEN_BASE_10 UINT64_MAX_LEN_BASE_10

#endif

//=============================================================================
//	Functions that convert a string to integers - ASCII.
//=============================================================================
//MAXSI_LINK MAXSI_FORCE_INLINE int ReadIntA10(char* Input, size_t InputLength);
//MAXSI_LINK MAXSI_FORCE_INLINE int8_t ReadInt8A10(char* Input, size_t InputLength);
//MAXSI_LINK MAXSI_FORCE_INLINE int16_t ReadInt16A10(char* Input, size_t InputLength);
//MAXSI_LINK MAXSI_FORCE_INLINE int32_t ReadInt32A10(char* Input, size_t InputLength);
//MAXSI_LINK MAXSI_FORCE_INLINE int64_t ReadInt64A10(char* Input, size_t InputLength);

MAXSI_LINK MAXSI_FORCE_INLINE unsigned int ReadUIntA10(char* Input, size_t InputLength);
MAXSI_LINK MAXSI_FORCE_INLINE uint8_t ReadUInt8A10(char* Input, size_t InputLength);
MAXSI_LINK MAXSI_FORCE_INLINE uint16_t ReadUInt16A10(char* Input, size_t InputLength);
MAXSI_LINK MAXSI_FORCE_INLINE uint32_t ReadUInt32A10(char* Input, size_t InputLength);
MAXSI_LINK MAXSI_FORCE_INLINE uint64_t ReadUInt64A10(char* Input, size_t InputLength);

MAXSI_LINK MAXSI_FORCE_INLINE unsigned int ReadUIntA16(char* Input, size_t InputLength);
MAXSI_LINK MAXSI_FORCE_INLINE uint8_t ReadUInt8A16(char* Input, size_t InputLength);
MAXSI_LINK MAXSI_FORCE_INLINE uint16_t ReadUInt16A16(char* Input, size_t InputLength);
MAXSI_LINK MAXSI_FORCE_INLINE uint32_t ReadUInt32A16(char* Input, size_t InputLength);
MAXSI_LINK MAXSI_FORCE_INLINE uint64_t ReadUInt64A16(char* Input, size_t InputLength);

//=============================================================================
//	Functions that convert a string to integers - Wide Chars.
//=============================================================================
//MAXSI_LINK MAXSI_FORCE_INLINE int ReadIntW10(wchar_t* Input, size_t InputLength);
//MAXSI_LINK MAXSI_FORCE_INLINE int8_t ReadInt8W10(wchar_t* Input, size_t InputLength);
//MAXSI_LINK MAXSI_FORCE_INLINE int16_t ReadInt16W10(wchar_t* Input, size_t InputLength);
//MAXSI_LINK MAXSI_FORCE_INLINE int32_t ReadInt32W10(wchar_t* Input, size_t InputLength);
//MAXSI_LINK MAXSI_FORCE_INLINE int64_t ReadInt64W10(wchar_t* Input, size_t InputLength);

MAXSI_LINK MAXSI_FORCE_INLINE unsigned int ReadUIntW10(wchar_t* Input, size_t InputLength);
MAXSI_LINK MAXSI_FORCE_INLINE uint8_t ReadUInt8W10(wchar_t* Input, size_t InputLength);
MAXSI_LINK MAXSI_FORCE_INLINE uint16_t ReadUInt16W10(wchar_t* Input, size_t InputLength);
MAXSI_LINK MAXSI_FORCE_INLINE uint32_t ReadUInt32W10(wchar_t* Input, size_t InputLength);
MAXSI_LINK MAXSI_FORCE_INLINE uint64_t ReadUInt64w10(wchar_t* Input, size_t InputLength);

MAXSI_LINK MAXSI_FORCE_INLINE unsigned int ReadUIntW16(wchar_t* Input, size_t InputLength);
MAXSI_LINK MAXSI_FORCE_INLINE uint8_t ReadUInt8W16(wchar_t* Input, size_t InputLength);
MAXSI_LINK MAXSI_FORCE_INLINE uint16_t ReadUInt16W16(wchar_t* Input, size_t InputLength);
MAXSI_LINK MAXSI_FORCE_INLINE uint32_t ReadUInt32W16(wchar_t* Input, size_t InputLength);
MAXSI_LINK MAXSI_FORCE_INLINE uint64_t ReadUInt64W16(wchar_t* Input, size_t InputLength);

//=============================================================================
//	Functions that find the length of their input.
//=============================================================================
MAXSI_LINK MAXSI_FORCE_INLINE size_t IntLength10(int Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t Int8Length10(int8_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t Int16Length10(int16_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t Int32Length10(int32_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t Int64Length10(int64_t Input);

MAXSI_LINK MAXSI_FORCE_INLINE size_t UIntLength10(unsigned int Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t UInt8Length10(uint8_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t UInt16Length10(uint16_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t UInt32Length10(uint32_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t UInt64Length10(uint64_t Input);

MAXSI_LINK MAXSI_FORCE_INLINE size_t UIntLength16(int Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t UInt8Length16(uint8_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t UInt16Length16(uint16_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t UInt32Length16(uint32_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t UInt64Length16(uint64_t Input);

MAXSI_LINK MAXSI_FORCE_INLINE size_t SizeLength10(size_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t SizeLength16(size_t Input);

//=============================================================================
//	Functions that print the input - ASCII.
//=============================================================================
MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintUIntA10(char* Dest, unsigned int Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintUInt8A10(char* Dest, uint8_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintUInt16A10(char* Dest, uint16_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintUInt32A10(char* Dest, uint32_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintUInt64A10(char* Dest, uint64_t Input);

MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintUIntA16X(char* Dest, unsigned int Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintUInt8A16X(char* Dest, uint8_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintUInt16A16X(char* Dest, uint16_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintUInt32A16X(char* Dest, uint32_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintUInt64A16X(char* Dest, uint64_t Input);

MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintSizeA10(char* Dest, size_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintSizeA16X(char* Dest, size_t Input);

//=============================================================================
//	Functions that print the input - Wide Chars.
//=============================================================================
MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintUIntW10(wchar_t* Dest, unsigned int Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintUInt8W10(wchar_t* Dest, uint8_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintUInt16W10(wchar_t* Dest, uint16_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintUInt32W10(wchar_t* Dest, uint32_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintUInt64W10(wchar_t* Dest, uint64_t Input);

MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintUIntW16X(wchar_t* Dest, unsigned int Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintUInt8W16X(wchar_t* Dest, uint8_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintUInt16W16X(wchar_t* Dest, uint16_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintUInt32W16X(wchar_t* Dest, uint32_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintUInt64W16X(wchar_t* Dest, uint64_t Input);

MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintSizeW10(wchar_t* Dest, size_t Input);
MAXSI_LINK MAXSI_FORCE_INLINE size_t PrintSizeW16X(wchar_t* Dest, size_t Input);

//=============================================================================
//	Functions that print a formatted from from input.
//=============================================================================
MAXSI_LINK char* TestPrintStringA(char* Format, ...);
MAXSI_LINK size_t TestPrintStringALength(char* Format, size_t FormatLen, va_list Arguments);

EndMaxsiNamespace

